What do we need to build our short medium view on crypto space
TODO:
Completed:
Big Narratives
%%capture
# imports
import panel as pn
pn.extension('plotly')
import plotly.express as px
from plotly.subplots import make_subplots
import plotly.graph_objects as go
from datetime import datetime
import pandas as pd
import hvplot.pandas
import matplotlib.pyplot as plt
import os
from pathlib import Path
from dotenv import load_dotenv
import json
import requests
import numpy as np
load_dotenv()
API_KEY = os.getenv("glassnode_api_key")
TWITTER_API_KEY = os.getenv("TWITTER_API_KEY")
TWITTER_SECRET = os.getenv("TWITTER_SECRET")
API_KEY = os.getenv("glassnode_api_key")
# make API request
res = requests.get('https://api.glassnode.com/v1/metrics/indicators/sopr',
params={'a': 'BTC', 'api_key': API_KEY})
# convert to pandas dataframe
df = pd.read_json(res.text, convert_dates=['t'])
res = requests.get('https://api.glassnode.com/v2/metrics/endpoints',
params={'api_key': API_KEY})
df = pd.read_json(res.text, convert_dates=['t'])
for idx,row in df.iterrows():
if 'ssr' in row['path']:
print(idx,row['path'],row['tier'])
179 /v1/metrics/indicators/ssr 2
def glassnode_request(symbol,metric,exchanges=None):
params={'a': symbol,'api_key': API_KEY}
if exchanges:
params['category'] = 'Exchanges'
df = pd.DataFrame()
for exch in exchanges:
params['e'] = exch
res = requests.get(f'https://api.glassnode.com/v1/metrics/{metric}', params)
exch_df = pd.read_json(res.text, convert_dates=['t'])
exch_df.set_index('t',inplace=True)
exch_df.rename(columns={'v':exch},inplace=True)
if len(df)==0:
df = exch_df
else:
df = pd.concat([df,exch_df],join='outer',axis='columns')
else:
res = requests.get(f'https://api.glassnode.com/v1/metrics/{metric}', params)
df = pd.read_json(res.text, convert_dates=['t'])
df.set_index('t',inplace=True)
return df
def plot_two_axes(data,col1,col2,title):
# Create figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# Add traces
fig.add_trace(
go.Scatter(x=data.index, y=data[col1],name=col1),
secondary_y=False,
)
fig['layout']['yaxis2']['showgrid'] = False
#Add traces
fig.add_trace(
go.Scatter(x=data.index, y=data[col2],name=col2),
secondary_y=True,
)
# Add figure title
fig.update_layout(
title_text=f"{title}",height=500
)
fig.show()
metric = 'transactions/transfers_volume_exchanges_net'
symbol = 'BTC'
exchanges = ['binance','huobi','coinbase','kraken','aggregated']
exch_flows = glassnode_request(symbol,metric,exchanges)
metric = 'distribution/balance_exchanges'
exchanges = None
btc_exch_balances = glassnode_request('BTC',metric,exchanges)
eth_exch_balances = glassnode_request('ETH',metric,exchanges)
usdt_exch_balances = glassnode_request('USDT',metric,exchanges)
metric = 'market/price_usd'
exchanges = None
btc_price = glassnode_request('btc',metric,exchanges)
eth_price = glassnode_request('eth',metric,exchanges)
data = btc_exch_balances.tail(365).copy()
data.loc[data.index, 'price'] = 1
data.loc[data.index,'price'] = btc_price.loc[data.index, 'v']
data.rename(columns={'v':'exchange_balance'}, inplace=True)
plot_two_axes(data,'exchange_balance','price','Exchange Balances BTC')
data = eth_exch_balances.tail(365).copy()
data.loc[data.index,'price'] = eth_price.loc[data.index,'v']
data.rename(columns={'v':'exchange_balance'},inplace=True)
plot_two_axes(data,'exchange_balance','price','Exchange Balances ETH')
data = usdt_exch_balances.tail(365).copy()
data.loc[data.index,'price'] = btc_price.loc[data.index,'v']
data.rename(columns={'v':'exchange_balance'},inplace=True)
plot_two_axes(data,'exchange_balance','price','Exchange Balances USDT')
data = exch_flows.ewm(halflife=10).mean().tail(365)
fig = px.line(data, x=data.index, y=data.columns)
fig.update_layout(height=500)
fig.update_yaxes(title_text='Net BTC')
fig.update_layout(title_text=f"Exchange Inflow/Outflow")
fig.show()
# Are the binance coins going to collateral or are they being sold?
def get_exchange_flows(symbol):
res = requests.get('https://api.glassnode.com/v1/metrics/transactions/transfers_volume_to_exchanges_sum', params={'a': symbol,'api_key': API_KEY})
exch = pd.read_json(res.text, convert_dates=['t'])
exch.set_index('t',inplace=True)
res = requests.get('https://api.glassnode.com/v1/metrics/transactions/transfers_volume_from_exchanges_sum', params={'a': symbol,'api_key': API_KEY})
from_exch = pd.read_json(res.text, convert_dates=['t'])
from_exch.set_index('t',inplace=True)
res = requests.get('https://api.glassnode.com/v1/metrics/market/price_usd', params={'a': symbol,'api_key': API_KEY})
price = pd.read_json(res.text, convert_dates=['t'])
price.set_index('t',inplace=True)
exch['from'] = from_exch['v']
exch.rename(columns={'v':'to'},inplace=True)
exch['net'] = exch['to'] - exch['from']
exch['price'] = price['v']
exch['net_ma'] = exch['net'].ewm(halflife=10).mean()
exch['symbol'] = symbol
exch.index.name = symbol
return exch
# Choices for Below:
# BTC, ETH, AAVE, ABT, AGI, AMPL, ANT, ARMOR, BADGER, BAL, BAND, BAT, BIX, BNT, BOND, BRD, BUSD, BZRX, CELR, CHSB, CND,
# COMP, CREAM, CRO, CRV, CVC, CVP, DAI, DENT, DGTX, DGX, DHT, DMG, DODO, DRGN, ELF, ENG, ENJ, EURS, FET, FTT, FUN, GNO,
# GUSD, HEGIC, HOT, HPT, HT, HUSD, KCS, KNC, LAMB, LBA, LDO, LEO, LINK, LOOM, LRC, MANA, MATIC, MCB, MCO, MFT, MIR, MKR,
# MLN, MTA, MTL, MX, NEXO, NFTX, NMR, NPXS, Nsure, OCEAN, OKB, OMG, PAX, PAY, PERP, PICKLE, PNK, PNT, POLY, POWR, PPT,
# QASH, QKC, QNT, RDN, REN, REP, RLC, ROOK, RSR, SAI, SAN, SNT, SNX, STAKE, STORJ, sUSD, SUSHI, TEL, TOP, UBT, UMA, UNI,
# USDC, USDK, USDT, UTK, VERI, WaBi, WAX, WBTC, WETH, wNMX, WTC, YAM, YFI, ZRX
btc_exch = get_exchange_flows('BTC')
eth_exch = get_exchange_flows('ETH')
usdt_exch = get_exchange_flows('USDT')
usdt_exch['price'] = btc_exch['price']
AAVE_exch = get_exchange_flows('AAVE')
LINK_exch = get_exchange_flows('LINK')
all_exch_flows = pd.concat([btc_exch,eth_exch,usdt_exch,AAVE_exch.tail(180),LINK_exch.tail(180)])
all_exch_flows.index.name = 'date'
def plot_exch_flows(exch,num_days=365):
symbol = exch.index.name
data = exch.tail(num_days)
# Create figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# Add traces
fig.add_trace(
go.Bar(x=data.index, y=data['net'], name="Inflow/Outflow"),
secondary_y=False,
)
fig['layout']['yaxis2']['showgrid'] = False
# Add traces
fig.add_trace(
go.Scatter(x=data.index, y=data['price'], name="Price"),
secondary_y=True,
)
# Add figure title
fig.update_layout(
title_text=f"Exchange Inflow/Outflow ({symbol})",height=500
)
fig.show()
plot_exch_flows(btc_exch.tail(60))
plot_exch_flows(eth_exch.tail(60))
plot_exch_flows(usdt_exch.tail(60))
plot_exch_flows(AAVE_exch.tail(180))
plot_exch_flows(LINK_exch.tail(180))
res = requests.get('https://api.glassnode.com/v1/metrics/derivatives/futures_funding_rate_perpetual_all', params={'a': 'BTC','api_key': API_KEY})
perps = pd.read_json(res.text, convert_dates=['t'])
perps.set_index('t',inplace=True)
perps = perps['o'].apply(pd.Series)*100*100
SSR = Bitcoin Marketcap / Stablecoin Marketcap. \ Covers the following Stable coins: USDT, TUSD, USDC, PAX, GUSD, DAI, SAI, and BUSD.
metric = 'indicators/ssr'
exchanges = None
btc_ssr = glassnode_request('BTC',metric,exchanges)
data = btc_ssr.tail(365).copy()
data.loc[data.index,'price'] = btc_price.loc[data.index,'v']
data.rename(columns={'v':'ssr'},inplace=True)
plot_two_axes(data,'ssr','price','Stable Coin Supply Ratio')
metric = 'indicators/sopr_adjusted'
exchanges = None
btc_sopr = glassnode_request('BTC',metric,exchanges)
data = btc_sopr.tail(365).copy()
data.loc[data.index,'price'] = btc_price.loc[data.index,'v']
data.rename(columns={'v':'sopr'},inplace=True)
plot_two_axes(data,'sopr','price','Adjusted SOPR BTC')
metric = 'indicators/nvts'
exchanges = None
btc_nvt = glassnode_request('BTC',metric,exchanges)
eth_nvt = glassnode_request('ETH',metric,exchanges)
data = btc_nvt.tail(365).copy()
data.loc[data.index,'price'] = btc_price.loc[data.index,'v']
data.rename(columns={'v':'nvt_signal'},inplace=True)
plot_two_axes(data,'nvt_signal','price','NVT Signal BTC')
data = eth_nvt.tail(365).copy()
data.loc[data.index,'price'] = eth_price.loc[data.index,'v']
data.rename(columns={'v':'nvt_signal'},inplace=True)
plot_two_axes(data,'nvt_signal','price','NVT Signal ETH')
fig = px.line(perps['mean'],title='Average Funding Rate')
fig.update_yaxes(title_text='Funding Rate (Bps)')
# Add figure title
fig.update_layout(height=700)
fig = px.line(perps, x=perps.index, y=perps.columns)
fig.update_layout(height=700)
fig.update_yaxes(title_text='Funding Rate (Bps)')
fig.show()
res = requests.get('https://api.glassnode.com/v1/metrics/derivatives/futures_open_interest_perpetual_sum_all', params={'a': 'BTC','api_key': API_KEY})
opint = pd.read_json(res.text, convert_dates=['t'])
opint.set_index('t',inplace=True)
opint = opint['o'].apply(pd.Series)
fig = px.line(opint, x=opint.index, y=opint.columns)
fig.update_layout(height=700)
fig.update_yaxes(title_text='Num Contracts')
fig.show()
import ccxt
import pandas as pd
exchange_id = 'binance'
exchange_class = getattr(ccxt, exchange_id)
exchange = exchange_class({
'apiKey': '',
'secret': '',
'timeout': 30000,
'enableRateLimit': True,
})
exchange.options = {'defaultType': 'delivery','adjustForTimeDifference': True,'defaultTimeInForce': 'GTC'}
markets = exchange.load_markets() # Load the futures markets
f_exchange = exchange_class({'apiKey': '','secret': '','timeout': 30000, 'enableRateLimit': True,})
f_exchange.options = {'defaultType': 'futures','adjustForTimeDifference': True}
btc_markets = [m for m in markets if 'BTC' in m]
eth_markets = [m for m in markets if 'ETH' in m]
def get_mid(symbol):
bidask = exchange.fetch_bids_asks(symbol, params={})[symbol]
return 0.5*bidask['bid'] + 0.5*bidask['ask']
header = ['Timestamp', 'Open', 'High', 'Low', 'Close', 'Volume']
ccxt_btc = pd.DataFrame(exchange.fetch_ohlcv('BTC/USD','1d'),columns=header)
min90d = float(ccxt_btc['Low'].tail(90).min())
max90d = float(ccxt_btc['High'].tail(90).max())
last = float(ccxt_btc['Close'].tail(1).max())
print(f"Bitcoin is trading ${last:,.2f}, which is ${max90d-last:,.2f} below its 90day high and ${last-min90d:,.2f} above its 90day low.")
Bitcoin is trading $35,388.10, which is $29,641.80 below its 90day high and $8,144.10 above its 90day low.
def create_yield_curve(markets, exchange):
spot = get_mid(markets[0])
spot_name = markets[0]
df = pd.DataFrame([], index = markets)
df.index.name = exchange
for m in markets:
price = get_mid(m)
df.loc[(m, 'price')] = price
if m == spot_name:
continue
df.loc[(m, 'days_to_expiry')] = (datetime.strptime(m.split('_')[1],'%y%m%d') - datetime.utcnow()).days
df.loc[(m, 'annualized_premium')] = np.log(price/spot)*365/df.loc[m, 'days_to_expiry'] * 100
return df
create_yield_curve(btc_markets, 'binance')
| price | days_to_expiry | annualized_premium | |
|---|---|---|---|
| binance | |||
| BTC/USD | 35397.45 | NaN | NaN |
| BTCUSD_210625 | 35400.25 | 24.0 | 0.120296 |
| BTCUSD_210924 | 36279.15 | 115.0 | 7.808909 |
create_yield_curve(eth_markets, 'binance')
| price | days_to_expiry | annualized_premium | |
|---|---|---|---|
| binance | |||
| ETH/USD | 2368.735 | NaN | NaN |
| ETHUSD_210625 | 2372.405 | 24.0 | 2.354480 |
| ETHUSD_210924 | 2428.855 | 115.0 | 7.955062 |
def binance_futures_oi(symbol):
# Coin margined Futures
params = {'pair':f'{symbol}USD','contractType':'ALL','period':'4h','limit':100}
opint = pd.DataFrame(exchange.dapiData_get_openinteresthist(params))
opint.index = pd.to_datetime(opint['timestamp'],unit='ms')
opint['coin-m_OI'] = opint['sumOpenInterestValue'].astype(float)
# USDT margined Futures
params = {'symbol':f'{symbol}USDT','pair':f'{symbol}USDT','contractType':'ALL','period':'4h','limit':100}
fopint = pd.DataFrame(f_exchange.fapiData_get_openinteresthist(params))
fopint.index = pd.to_datetime(fopint['timestamp'],unit='ms')
opint['usdt-m_OI'] = fopint['sumOpenInterest'].astype(float)
fig = px.line(opint, x=opint.index, y=['coin-m_OI','usdt-m_OI'])
fig.update_layout(title_text=f"Binance: {symbol} Open Interest", height=700)
fig.update_yaxes(title_text=f'Num of {symbol}')
fig.show()
return opint
btc_opint = binance_futures_oi('BTC')
eth_opint = binance_futures_oi('ETH')
import time
now_str = str(int(time.time())*1000)
# Get active options
req_url = 'https://deribit.com/api/v2/public/get_volatility_index_data'
params = {"currency": "BTC","resolution": "1D","start_timestamp": "1599373800000","end_timestamp": now_str}
r = requests.get(req_url,params)
data = r.json()
vol_index = pd.DataFrame(data['result'])
vol_index = pd.DataFrame(vol_index.data.tolist(), index= vol_index.index,columns = ['time','open','high','low','close'])
vol_index.index = pd.to_datetime(vol_index['time'],unit='ms')
fig = px.line(vol_index, x=vol_index.index, y=['close','low','high'])
fig.update_layout(height=700,title_text='Deribit Vol Index')
fig.update_yaxes(title_text='Vol Index')
fig.show()
import yfinance as yf
today = pd.to_datetime("today").strftime("%Y-%m-%d")
data = yf.download("SPY ^TNX MGC=F NQ=F DX-Y.NYB BTC-USD", start="2020-01-01", end=today)
data = data['Close'].dropna()
[*********************100%***********************] 6 of 6 completed
for col in data.columns:
if col != 'BTC-USD':
plot_two_axes(data,col,'BTC-USD',f'BTC vc {col}')
DEFI_API_KEY = "824d4b3157be6c75e79982be9f7ee822770f37d5aa6542fcb260ce492375"
r = requests.get(
"https://data-api.defipulse.com/api/v1/defipulse/api/getLendingHistory?",
params={
'api-key': DEFI_API_KEY
}
)
print(r.status_code)
df = pd.DataFrame(json.loads(r.content.decode()))
df.timestamp = pd.to_numeric(df.timestamp, errors='coerce')
df = df.dropna()
df['date'] = pd.to_datetime(df.timestamp, unit='s').dt.date
def get_usdt(r, which="USDT"):
try:
return r[which]['USD']
except:
return 0
df['usdt'] = df.outstanding.apply(get_usdt, which="USDT")
df['total'] = df.outstanding.apply(get_usdt, which="total")
200
borrow_rates = df['borrow_rates'].apply(pd.Series)
borrow_rates.index = pd.to_datetime(df['timestamp'],unit='s')
lend_rates = df['lend_rates'].apply(pd.Series)
lend_rates.index = pd.to_datetime(df['timestamp'],unit='s')
outstanding = df['outstanding'].apply(pd.Series)
outstanding.index = pd.to_datetime(df['timestamp'],unit='s')
data = borrow_rates.head(90)
fig = px.line(data, x=data.index, y=data.columns)
fig.update_layout(height=700,title_text='Defi Borrow Rates')
fig.update_yaxes(title_text='APY')
fig.show()
data = lend_rates.head(90)
fig = px.line(data, x=data.index, y=data.columns)
fig.update_layout(height=700,title_text='Defi Lending Rates')
fig.update_yaxes(title_text='APY')
fig.show()
tvl = pd.DataFrame(columns=outstanding.columns,index=outstanding.index)
for col in outstanding.columns:
tvl[col] = outstanding[col].apply(pd.Series)['USD']
data = tvl.loc[:,tvl.mean()>10000000].head(90)
fig = px.line(data, x=data.index, y=data.columns)
fig.update_layout(height=700,title_text='Defi Total Value Locked')
fig.update_yaxes(title_text='Total Value Locked')
fig.show()
whale_api_key = '9saZihVYIHkv3YdVwsqzlcKCqSIDPD0i'
now_str = str(int(time.time())-3000)
url = f"https://api.whale-alert.io/v1/transactions?api_key={whale_api_key}&min_value=1000000&start={now_str}"
import requests
resp = requests.get(url)
from nbconvert import HTMLExporter
import codecs
import nbformat
notebook_name = 'ShortTerm.ipynb'
output_file_name = 'output.html'
exporter = HTMLExporter()
output_notebook = nbformat.read(notebook_name, as_version=4)
output, resources = exporter.from_notebook_node(output_notebook)
codecs.open(output_file_name, 'w', encoding='utf-8').write(output)